package cz.possoft.boot;

import java.lang.reflect.Method;

/**
 * Main entry point for PossoftNet applications. It contains main method for run application and this method
 * 1) sets base classloader (all jars from lib directory)
 * 2) Initialize IOC framework (JBoss Microcontainer) 
 * 3) Delegates running to given Executor class. 
 * 
 * So Executor class and it's "run" method has access to all classes in lib directory.
 * 
 * @author mposolda
 */
public class MainClass {
	
	public static void main(String[] args) throws Exception
	{
		System.out.println("Running MainClass.main");
		
		// get classloader for all jars in "lib" directory.
		ClassLoader mainClassLoader;
		try 
		{
			mainClassLoader = BootClassLoaderUtils.getInstanceForDirectory("lib");
		}
		catch (Exception e)
		{
			// defaults to system classLoader if "lib" directory does not exists.
			mainClassLoader = ClassLoader.getSystemClassLoader();
		}
		Thread.currentThread().setContextClassLoader(mainClassLoader);
		
		// boot ComponentManager (main IOC component) and initialize all services.
		System.out.println("Start of deployment of components.");
		getInitializedComponentManager();
		System.out.println("Deployment finished.");
		
		// get executor class and invoke run.
		Object executor = getExecutor();
		System.out.println("Running executor. Executor is " + executor);
		runExecutor(executor, args);
	}
	
	/**
	 * Get initialized component manager via reflection. It calls: MainFactory.getInstance().getComponentManagerInstance()
	 * 
	 * @return
	 * @throws Exceptio
	 */
	private static Object getInitializedComponentManager() throws Exception
	{
		ClassLoader currentCl = Thread.currentThread().getContextClassLoader();
		Class<?> mainFactoryClass = currentCl.loadClass("cz.possoft.base.MainFactory");
		Method getInstance = mainFactoryClass.getMethod("getInstance", null);
		Object mainFactory = getInstance.invoke(null, null);
		Method getComponentManagerInstance = mainFactory.getClass().getMethod("getComponentManagerInstance", null);
		Object componentManager = getComponentManagerInstance.invoke(mainFactory, null);
		return componentManager;
	}
	
	/**
	 * get Executor instance from container layer.
	 * 
	 * @return
	 * @throws Exception
	 */
	private static Object getExecutor() throws Exception
	{
		// get executor
		Object componentManager = getInitializedComponentManager();
		Method getComponentInstanceByType = componentManager.getClass().getMethod("getComponentInstanceByType", Class.class);
		return getComponentInstanceByType.invoke(componentManager, Thread.currentThread().getContextClassLoader().loadClass("cz.possoft.base.Executor"));
		
	}
	
	/**
	 * Invoke run method on given executor.
	 * 
	 * @param executorObj
	 * @param args
	 * @throws Exception
	 */
	private static void runExecutor(Object executorObj, String[] args) throws Exception
	{
		Method run = executorObj.getClass().getMethod("run", String[].class); 
		run.invoke(executorObj, new Object[] { args });		
	}

}
